﻿namespace In66.Net.Consul.Extensions;

public static class ServiceCollectionExtension
{
    private static readonly ConcurrentDictionary<string, char> s_RegisteredModels = new();

    public static bool HasRegistered(this IServiceCollection _, string modelName) => !s_RegisteredModels.TryAdd(modelName.ToLower(), '1');

    internal static T? GetSingletonInstanceOrNull<T>(this IServiceCollection services)
        where T : class
    {
        var instance = services.FirstOrDefault(d => d.ServiceType == typeof(T))?.ImplementationInstance;
        if (instance is null)
        {
            return null;
        }

        return (T)instance;
    }

    internal static T GetSingletonInstance<T>(this IServiceCollection services)
        where T : class
    {
        var instance = services.GetSingletonInstanceOrNull<T>();
        if (instance is null)
        {
            throw new InvalidOperationException("Could not find singleton service: " + typeof(T).AssemblyQualifiedName);
        }

        return instance;
    }

    public static IServiceCollection AddInfraConsul(this IServiceCollection services, IConfigurationSection consulSection, IConfigurationSection kestrelSection)
    {
        if (services.HasRegistered(nameof(AddInfraConsul)))
        {
            return services;
        }

        return services
            .Configure<ConsulConfig>(consulSection)
            .Configure<KestrelConfig>(kestrelSection)
            .AddSingleton(provider =>
            {
                var configOptions = provider.GetService<IOptions<ConsulConfig>>();
                if (configOptions is null)
                {
                    throw new NullReferenceException(nameof(configOptions));
                }

                return new ConsulClient(x => x.Address = new Uri(configOptions.Value.ConsulUrl));
            });
    }
}